package com.ibis.debuglistwidget;


import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

/**
 * Our data observer just notifies an update for all Log widgets when it detects
 * a change.
 */
class LogDataProviderObserver extends ContentObserver {

    private static final String TAG = LogDataProviderObserver.class
            .getSimpleName();
    private AppWidgetManager mAppWidgetManager;
    private ComponentName mComponentName;

    LogDataProviderObserver(AppWidgetManager mgr, ComponentName cn, Handler h) {
        super(h);
        mAppWidgetManager = mgr;
        mComponentName = cn;
    }

    @Override
    public void onChange(boolean selfChange) {
        // The data has changed, so notify the widget that the collection view
        // needs to be updated.
        // In response, the factory's onDataSetChanged() will be called which
        // will requery the
        // cursor for the new data.
        Log.d(TAG, "onChange|notifyAppWidgetViewDataChanged");
        mAppWidgetManager.notifyAppWidgetViewDataChanged(
                mAppWidgetManager.getAppWidgetIds(mComponentName),
                R.id.log_list);
    }
}

/**
 * The Log widget's AppWidgetProvider.
 */
public class LogWidgetProvider extends AppWidgetProvider {

    private static final String TAG = LogWidgetProvider.class.getSimpleName();
    public static String SETTINGS = "com.ibis.debuglistwidget.SETTINGS";
    public static String CLICK_ACTION = "com.ibis.debuglistwidget.CLICK";
    public static String REFRESH_ACTION = "com.ibis.debuglistwidget.REFRESH";
    public static String FORCE_WIDGET_UPDATE = "com.ibis.debuglistwidget.loglistwidget.WIDGET_UPDATE";
    public static String EXTRA_LOG_ID = "com.ibis.debuglistwidget.loglistwidget.log";
    private static HandlerThread sWorkerThread;
    private static Handler sWorkerQueue;
    // private static final int REFRESH_RATE = 150000;
    private Prefs mPrefs = null;

    // private static LogDataProviderObserver sDataObserver;

    public LogWidgetProvider() {

        Log.d(TAG, "Start the worker thread");
        // Start the worker thread
        if (sWorkerThread == null) {
            sWorkerThread = new HandlerThread("LogWidgetProvider-worker");
            sWorkerThread.start();
            sWorkerQueue = new Handler(sWorkerThread.getLooper());
        }
        Log.d(TAG, "End the worker thread");
    }

    @Override
    public void onEnabled(Context context) {
        // Register for external updates to the data to trigger an update of the
        // widget. When using
        // content providers, the data is often updated via a background
        // service, or in response to
        // user interaction in the main app. To ensure that the widget always
        // reflects the current
        // state of the data, we must listen for changes and update ourselves
        // accordingly.

        Log.d(TAG, "onEnabled");
        // final ContentResolver r = context.getContentResolver();
        // if (sDataObserver == null) {
        // Log.d(TAG, "onEnabled|register Data Observer");
        // final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
        // final ComponentName cn = new ComponentName(context,
        // LogWidgetProvider.class);
        // sDataObserver = new LogDataProviderObserver(mgr, cn, sWorkerQueue);
        // r.registerContentObserver(LogDataProvider.CONTENT_URI, true,
        // sDataObserver);
        // }

        mPrefs = new Prefs(context);
        // Bind the click intent for the refresh button on the widget
        final Intent refreshIntent = new Intent(context,
                LogWidgetProvider.class);

        final AlarmManager mgr = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        // final Intent alarmIntent = new Intent(context,
        // LogWidgetProvider.class);
        refreshIntent.setAction(LogWidgetProvider.REFRESH_ACTION);
        final PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(
                context, 0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        mgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime(), mPrefs.getRefreshFrequency()
                .getValue() // REFRESH_RATE
                , alarmPendingIntent);

    }

    /*
     * (non-Javadoc)
     *
     * @see
     * android.appwidget.AppWidgetProvider#onDisabled(android.content.Context)
     */
    @Override
    public void onDisabled(Context context) {

        Log.d(TAG, "clearAlarm");
        AlarmManager alarmManager = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        final Intent refreshIntent = new Intent(context,
                LogWidgetProvider.class);
        refreshIntent.setAction(LogWidgetProvider.REFRESH_ACTION);
        // Bind the click intent for the refresh button on the widget

        // cancel the pending intent!
        // Intent alarmIntent = new Intent(LogWidgetProvider.REFRESH_ACTION);
        PendingIntent pIntent = PendingIntent.getBroadcast(context, 0,
                refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        alarmManager.cancel(pIntent);

        super.onDisabled(context);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * android.appwidget.AppWidgetProvider#onDeleted(android.content.Context,
     * int[])
     */
    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        Log.d(TAG, "onDeleted");
        super.onDeleted(context, appWidgetIds);
    }

    @Override
    public void onReceive(Context ctx, Intent intent) {

        Log.d(TAG, "onReceive");

        final String action = intent.getAction();
        if (action.equals(REFRESH_ACTION)) {
            // BroadcastReceivers have a limited amount of time to do work, so
            // for this sample, we
            // are triggering an update of the data on another thread. In
            // practice, this update
            // can be triggered from a background service, or perhaps as a
            // result of user actions
            // inside the main application.
            final Context context = ctx;
            Log.d(TAG, "onReceive|posting Runnable");
            sWorkerQueue.removeMessages(0);
            sWorkerQueue.post(new Runnable() {
                @Override
                public void run() {
                    // final ContentResolver r = context.getContentResolver();
                    // final Cursor c = r.query(LogDataProvider.CONTENT_URI,
                    // null,
                    // null, null, null);

                    Log.d(TAG, "onReceive|run");
                    final AppWidgetManager mgr = AppWidgetManager
                            .getInstance(context);
                    final ComponentName cn = new ComponentName(context,
                            LogWidgetProvider.class);
                    Log.d(TAG, "onReceive|notifyAppWidgetViewDataChanged");
                    mgr.notifyAppWidgetViewDataChanged(mgr.getAppWidgetIds(cn),
                            R.id.log_list);
                }
            });
        } else if (action.equals(CLICK_ACTION)) {
            // Show a toast
            Log.d(TAG, "onReceive|click");
            // final int appWidgetId = intent.getIntExtra(
            // AppWidgetManager.EXTRA_APPWIDGET_ID,
            // AppWidgetManager.INVALID_APPWIDGET_ID);
            final String log = intent.getStringExtra(EXTRA_LOG_ID);
            final String formatStr = ctx.getResources().getString(
                    R.string.toast_format_string);
            Toast.makeText(ctx, String.format(formatStr, log),
                    Toast.LENGTH_SHORT).show();
        } else if (action.equals(FORCE_WIDGET_UPDATE)) {
            // Show a toast
            Log.d(TAG, "onReceive|force_widget_update");
            // final int appWidgetId = intent.getIntExtra(
            // AppWidgetManager.EXTRA_APPWIDGET_ID,
            // AppWidgetManager.INVALID_APPWIDGET_ID);
            final String log = intent.getStringExtra(EXTRA_LOG_ID);
            final String formatStr = ctx.getResources().getString(
                    R.string.toast_format_string);
            Toast.makeText(ctx, String.format(formatStr, log),
                    Toast.LENGTH_SHORT).show();
        } else if (action.equals(SETTINGS)) {
            Log.d(TAG, "onReceive|settings");

            int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

            final String formatStr = ctx.getResources().getString(
                    R.string.toast_format_string);
            Toast.makeText(ctx, String.format(formatStr, "settings!"),
                    Toast.LENGTH_SHORT).show();

            // Find the widget id from the intent.

            Bundle extras = intent.getExtras();
            if (extras != null) {
                mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
                        AppWidgetManager.INVALID_APPWIDGET_ID);
            }


            Intent i = new Intent(ctx, PrefsActivity.class);
            i.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // Start PrefsActivity with appwidgetID
            ctx.startActivity(i);
        }

        super.onReceive(ctx, intent);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                         int[] appWidgetIds) {

        Log.d(TAG, "Widget_onUpdate|start");
        // Update each of the widgets with the remote adapter
        for (int i = 0; i < appWidgetIds.length; i++) {
            // Specify the service to provide data for the collection widget.
            // Note that we need to
            // embed the appWidgetId via the data otherwise it will be ignored.
            Intent intent = new Intent(context, LogWidgetService.class);
            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    appWidgetIds[i]);
            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
            RemoteViews rv = new RemoteViews(context.getPackageName(),
                    R.layout.widget_layout);
//            rv.setRemoteAdapter(appWidgetIds[i], R.id.log_list, intent); //deprecated
            rv.setRemoteAdapter(R.id.log_list, intent);

            // Set the empty view to be displayed if the collection is empty. It
            // must be a sibling
            // view of the collection view.
            rv.setEmptyView(R.id.log_list, R.id.empty_view);


            // Setting button
// Create an Intent to launch ExampleActivity
//            Intent settingIntent = new Intent(context, PrefsActivity.class);
//            PendingIntent onSettingPendingIntent = PendingIntent.getActivity(context, 1, settingIntent, 0);

            Intent onSettingIntent = new Intent(context,
                    LogWidgetProvider.class);
            onSettingIntent.setAction(LogWidgetProvider.SETTINGS);
            onSettingIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    appWidgetIds[i]);
//            onSettingIntent.setData(Uri.parse(onSettingIntent
//                    .toUri(Intent.URI_INTENT_SCHEME)));
            PendingIntent onSettingPendingIntent = PendingIntent
                    .getBroadcast(context, 0, onSettingIntent,
                            PendingIntent.FLAG_UPDATE_CURRENT);
            rv.setOnClickPendingIntent(R.id.imageButton, onSettingPendingIntent);

            // Bind a click listener template for the contents of the Log list.
            // Note that we
            // need to update the intent's data if we set an extra, since the
            // extras will be
            // ignored otherwise.
            Intent onClickIntent = new Intent(context,
                    LogWidgetProvider.class);
            onClickIntent.setAction(LogWidgetProvider.CLICK_ACTION);
            onClickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    appWidgetIds[i]);
//            onClickIntent.setData(Uri.parse(onClickIntent
//                    .toUri(Intent.URI_INTENT_SCHEME)));
            PendingIntent onClickPendingIntent = PendingIntent
                    .getBroadcast(context, 0, onClickIntent,
                            PendingIntent.FLAG_UPDATE_CURRENT);
            rv.setPendingIntentTemplate(R.id.log_list, onClickPendingIntent);

            Log.d(TAG, "onUpdate" + i);

            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
}